From: Étienne Mollier Date: Wed, 10 Dec 2025 21:27:34 +0000 (+0100) Subject: d/patches/*-CVE-2025-9732.patch: new. X-Git-Tag: archive/raspbian/3.6.9-6+rpi1^2~19 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22Programmet/%22http:/www.example.com/cgi/%22https:/%22Programmet?a=commitdiff_plain;h=422439ad51c8394366c24b3825db1b4a25632e69;p=dcmtk.git d/patches/*-CVE-2025-9732.patch: new. These changes pulled from dcmtk upstream address CVE-2025-9732. Closes: #1113993 --- diff --git a/debian/patches/0013-CVE-2025-9732.patch b/debian/patches/0013-CVE-2025-9732.patch new file mode 100644 index 00000000..4420127b --- /dev/null +++ b/debian/patches/0013-CVE-2025-9732.patch @@ -0,0 +1,397 @@ +Description: Fixed issue with invalid "YBR_FULL" DICOM images. + Fixed an issue when processing an invalid DICOM image with a Photometric + Interpretation of "YBR_FULL" and a Planar Configuration of "1" where + the number of pixels stored does not match the expected number of pixels + (much too less). Now, the pixel data of such an image is not processed + at all, but an empty image (black pixels) is created instead. The user + is warned about this by an appropriate log message. + . + Thanks to Ding zhengzheng for the report + and the sample file (PoC). +Author: Joerg Riesmeier +Applied-Upstream: 7ad81d69b19714936e18ea5fc74edaeb9f021ce7 +Reviewed-By: Étienne Mollier +Last-Update: 2025-08-15 + +--- dcmtk.orig/dcmimage/include/dcmtk/dcmimage/dicopxt.h ++++ dcmtk/dcmimage/include/dcmtk/dcmimage/dicopxt.h +@@ -574,7 +574,11 @@ + { + /* erase empty part of the buffer (=blacken the background) */ + if (InputCount < Count) +- OFBitmanipTemplate::zeroMem(Data[j] + InputCount, Count - InputCount); ++ { ++ const size_t count = (Count - InputCount); ++ DCMIMAGE_TRACE("filing empty part of the intermediate pixel data (" << count << " pixels) of plane " << j << " with value = 0"); ++ OFBitmanipTemplate::zeroMem(Data[j] + InputCount, count); ++ } + } else { + DCMIMAGE_DEBUG("cannot allocate memory buffer for 'Data[" << j << "]' in DiColorPixelTemplate::Init()"); + result = 0; // at least one buffer could not be allocated! +--- dcmtk.orig/dcmimage/include/dcmtk/dcmimage/diybrpxt.h ++++ dcmtk/dcmimage/include/dcmtk/dcmimage/diybrpxt.h +@@ -1,6 +1,6 @@ + /* + * +- * Copyright (C) 1998-2016, OFFIS e.V. ++ * Copyright (C) 1998-2025, OFFIS e.V. + * All rights reserved. See COPYRIGHT file for details. + * + * This software and supporting documentation were developed by +@@ -24,6 +24,7 @@ + #define DIYBRPXT_H + + #include "dcmtk/config/osconfig.h" ++#include "dcmtk/ofstd/ofbmanip.h" + + #include "dcmtk/dcmimage/dicopxt.h" + #include "dcmtk/dcmimgle/diinpx.h" /* gcc 3.4 needs this */ +@@ -90,179 +91,189 @@ + // use the number of input pixels derived from the length of the 'PixelData' + // attribute), but not more than the size of the intermediate buffer + const unsigned long count = (this->InputCount < this->Count) ? this->InputCount : this->Count; +- if (rgb) /* convert to RGB model */ ++ // make sure that there is sufficient input data (for planar pixel data) ++ if (!this->PlanarConfiguration || (count >= planeSize * 3 /* number of planes */)) + { +- T2 *r = this->Data[0]; +- T2 *g = this->Data[1]; +- T2 *b = this->Data[2]; +- const T2 maxvalue = OFstatic_cast(T2, DicomImageClass::maxval(bits)); +- DiPixelRepresentationTemplate rep; +- if (bits == 8 && !rep.isSigned()) // only for unsigned 8 bit ++ if (rgb) /* convert to RGB model */ + { +- Sint16 rcr_tab[256]; +- Sint16 gcb_tab[256]; +- Sint16 gcr_tab[256]; +- Sint16 bcb_tab[256]; +- const double r_const = 0.7010 * OFstatic_cast(double, maxvalue); +- const double g_const = 0.5291 * OFstatic_cast(double, maxvalue); +- const double b_const = 0.8859 * OFstatic_cast(double, maxvalue); +- unsigned long l; +- for (l = 0; l < 256; ++l) ++ T2 *r = this->Data[0]; ++ T2 *g = this->Data[1]; ++ T2 *b = this->Data[2]; ++ const T2 maxvalue = OFstatic_cast(T2, DicomImageClass::maxval(bits)); ++ DiPixelRepresentationTemplate rep; ++ if (bits == 8 && !rep.isSigned()) // only for unsigned 8 bit + { +- rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * OFstatic_cast(double, l) - r_const); +- gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * OFstatic_cast(double, l)); +- gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * OFstatic_cast(double, l) - g_const); +- bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * OFstatic_cast(double, l) - b_const); +- } +- Sint32 sr; +- Sint32 sg; +- Sint32 sb; +- if (this->PlanarConfiguration) +- { +-/* +- const T1 *y = pixel; +- const T1 *cb = y + this->InputCount; +- const T1 *cr = cb + this->InputCount; +- for (i = count; i != 0; --i, ++y, ++cb, ++cr) ++ Sint16 rcr_tab[256]; ++ Sint16 gcb_tab[256]; ++ Sint16 gcr_tab[256]; ++ Sint16 bcb_tab[256]; ++ const double r_const = 0.7010 * OFstatic_cast(double, maxvalue); ++ const double g_const = 0.5291 * OFstatic_cast(double, maxvalue); ++ const double b_const = 0.8859 * OFstatic_cast(double, maxvalue); ++ unsigned long l; ++ for (l = 0; l < 256; ++l) + { +- sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[*cr]); +- sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]); +- sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[*cb]); +- *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr); +- *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg); +- *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb); ++ rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * OFstatic_cast(double, l) - r_const); ++ gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * OFstatic_cast(double, l)); ++ gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * OFstatic_cast(double, l) - g_const); ++ bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * OFstatic_cast(double, l) - b_const); + } ++ Sint32 sr; ++ Sint32 sg; ++ Sint32 sb; ++ if (this->PlanarConfiguration) ++ { ++/* ++ const T1 *y = pixel; ++ const T1 *cb = y + this->InputCount; ++ const T1 *cr = cb + this->InputCount; ++ for (i = count; i != 0; --i, ++y, ++cb, ++cr) ++ { ++ sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[*cr]); ++ sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]); ++ sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[*cb]); ++ *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr); ++ *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg); ++ *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb); ++ } + */ +- const T1 *y = pixel; +- const T1 *cb = y + planeSize; +- const T1 *cr = cb + planeSize; +- unsigned long i = count; +- while (i != 0) ++ const T1 *y = pixel; ++ const T1 *cb = y + planeSize; ++ const T1 *cr = cb + planeSize; ++ unsigned long i = count; ++ while (i != 0) ++ { ++ /* convert a single frame */ ++ for (l = planeSize; (l != 0) && (i != 0); --l, --i, ++y, ++cb, ++cr) ++ { ++ sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[*cr]); ++ sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]); ++ sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[*cb]); ++ *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr); ++ *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg); ++ *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb); ++ } ++ /* jump to next frame start (skip 2 planes) */ ++ y += 2 * planeSize; ++ cb += 2 * planeSize; ++ cr += 2 * planeSize; ++ } ++ } ++ else + { +- /* convert a single frame */ +- for (l = planeSize; (l != 0) && (i != 0); --l, --i, ++y, ++cb, ++cr) ++ const T1 *p = pixel; ++ T1 y; ++ T1 cb; ++ T1 cr; ++ unsigned long i; ++ for (i = count; i != 0; --i) + { +- sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, *cr)]); +- sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, *cb)]) - OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, *cr)]); +- sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, *cb)]); ++ y = *(p++); ++ cb = *(p++); ++ cr = *(p++); ++ sr = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, rcr_tab[cr]); ++ sg = OFstatic_cast(Sint32, y) - OFstatic_cast(Sint32, gcb_tab[cb]) - OFstatic_cast(Sint32, gcr_tab[cr]); ++ sb = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, bcb_tab[cb]); + *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr); + *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg); + *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb); + } +- /* jump to next frame start (skip 2 planes) */ +- y += 2 * planeSize; +- cb += 2 * planeSize; +- cr += 2 * planeSize; + } + } + else + { +- const T1 *p = pixel; +- T1 y; +- T1 cb; +- T1 cr; +- unsigned long i; +- for (i = count; i != 0; --i) ++ if (this->PlanarConfiguration) ++ { ++/* ++ const T1 *y = pixel; ++ const T1 *cb = y + this->InputCount; ++ const T1 *cr = cb + this->InputCount; ++ for (i = count; i != 0; --i) ++ convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset), ++ removeSign(*(cr++), offset), maxvalue); ++*/ ++ unsigned long l; ++ unsigned long i = count; ++ const T1 *y = pixel; ++ const T1 *cb = y + planeSize; ++ const T1 *cr = cb + planeSize; ++ while (i != 0) ++ { ++ /* convert a single frame */ ++ for (l = planeSize; (l != 0) && (i != 0); --l, --i) ++ { ++ convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset), ++ removeSign(*(cr++), offset), maxvalue); ++ } ++ /* jump to next frame start (skip 2 planes) */ ++ y += 2 * planeSize; ++ cb += 2 * planeSize; ++ cr += 2 * planeSize; ++ } ++ } ++ else + { +- y = *(p++); +- cb = *(p++); +- cr = *(p++); +- sr = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, cr)]); +- sg = OFstatic_cast(Sint32, y) - OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, cb)]) - OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, cr)]); +- sb = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, cb)]); +- *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr); +- *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg); +- *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb); ++ const T1 *p = pixel; ++ T2 y; ++ T2 cb; ++ T2 cr; ++ unsigned long i; ++ for (i = count; i != 0; --i) ++ { ++ y = removeSign(*(p++), offset); ++ cb = removeSign(*(p++), offset); ++ cr = removeSign(*(p++), offset); ++ convertValue(*(r++), *(g++), *(b++), y, cb, cr, maxvalue); ++ } + } + } +- } +- else +- { ++ } else { /* retain YCbCr model */ ++ const T1 *p = pixel; + if (this->PlanarConfiguration) + { +-/* +- const T1 *y = pixel; +- const T1 *cb = y + this->InputCount; +- const T1 *cr = cb + this->InputCount; +- for (i = count; i != 0; --i) +- convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset), +- removeSign(*(cr++), offset), maxvalue); +-*/ ++ /* ++ T2 *q; ++ // number of pixels to be skipped (only applicable if 'PixelData' contains more ++ // pixels than expected) ++ const unsigned long skip = (this->InputCount > this->Count) ? (this->InputCount - this->Count) : 0; ++ for (int j = 0; j < 3; ++j) ++ { ++ q = this->Data[j]; ++ for (i = count; i != 0; --i) ++ *(q++) = removeSign(*(p++), offset); ++ // skip to beginning of next plane ++ p += skip; ++ } ++ */ + unsigned long l; +- unsigned long i = count; +- const T1 *y = pixel; +- const T1 *cb = y + planeSize; +- const T1 *cr = cb + planeSize; +- while (i != 0) ++ unsigned long i = 0; ++ while (i < count) + { +- /* convert a single frame */ +- for (l = planeSize; (l != 0) && (i != 0); --l, --i) ++ /* store current pixel index */ ++ const unsigned long iStart = i; ++ for (int j = 0; j < 3; ++j) + { +- convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset), +- removeSign(*(cr++), offset), maxvalue); ++ /* convert a single plane */ ++ for (l = planeSize, i = iStart; (l != 0) && (i < count); --l, ++i) ++ this->Data[j][i] = removeSign(*(p++), offset); + } +- /* jump to next frame start (skip 2 planes) */ +- y += 2 * planeSize; +- cb += 2 * planeSize; +- cr += 2 * planeSize; + } + } + else + { +- const T1 *p = pixel; +- T2 y; +- T2 cb; +- T2 cr; ++ int j; + unsigned long i; +- for (i = count; i != 0; --i) +- { +- y = removeSign(*(p++), offset); +- cb = removeSign(*(p++), offset); +- cr = removeSign(*(p++), offset); +- convertValue(*(r++), *(g++), *(b++), y, cb, cr, maxvalue); +- } ++ for (i = 0; i < count; ++i) /* for all pixel ... */ ++ for (j = 0; j < 3; ++j) ++ this->Data[j][i] = removeSign(*(p++), offset); /* ... copy planes */ + } + } +- } else { /* retain YCbCr model */ +- const T1 *p = pixel; +- if (this->PlanarConfiguration) +- { +-/* +- T2 *q; +- // number of pixels to be skipped (only applicable if 'PixelData' contains more +- // pixels than expected) +- const unsigned long skip = (this->InputCount > this->Count) ? (this->InputCount - this->Count) : 0; +- for (int j = 0; j < 3; ++j) +- { +- q = this->Data[j]; +- for (i = count; i != 0; --i) +- *(q++) = removeSign(*(p++), offset); +- // skip to beginning of next plane +- p += skip; +- } +-*/ +- unsigned long l; +- unsigned long i = 0; +- while (i < count) +- { +- /* store current pixel index */ +- const unsigned long iStart = i; +- for (int j = 0; j < 3; ++j) +- { +- /* convert a single plane */ +- for (l = planeSize, i = iStart; (l != 0) && (i < count); --l, ++i) +- this->Data[j][i] = removeSign(*(p++), offset); +- } +- } +- } +- else +- { +- int j; +- unsigned long i; +- for (i = 0; i < count; ++i) /* for all pixel ... */ +- for (j = 0; j < 3; ++j) +- this->Data[j][i] = removeSign(*(p++), offset); /* ... copy planes */ +- } ++ } else { ++ // do not process the input data, as it is too short ++ DCMIMAGE_WARN("input data is too short, filling the complete image with black pixels"); ++ // erase empty part of the buffer (that has not been "blackened" yet) ++ for (int j = 0; j < 3; ++j) ++ OFBitmanipTemplate::zeroMem(this->Data[j], count); + } + } + } +--- dcmtk.orig/dcmimgle/libsrc/dcmimage.cc ++++ dcmtk/dcmimgle/libsrc/dcmimage.cc +@@ -1,6 +1,6 @@ + /* + * +- * Copyright (C) 1996-2024, OFFIS e.V. ++ * Copyright (C) 1996-2025, OFFIS e.V. + * All rights reserved. See COPYRIGHT file for details. + * + * This software and supporting documentation were developed by +@@ -210,6 +210,7 @@ + *(q++) = c; + } + *q = '\0'; // end of C string ++ DCMIMGLE_DEBUG("filtered version of 'PhotometricInterpretation' = " << OFSTRING_GUARD(cstr)); + while ((pin->Name != NULL) && (strcmp(pin->Name, cstr) != 0)) + ++pin; + delete[] cstr; diff --git a/debian/patches/0014-CVE-2025-9732.patch b/debian/patches/0014-CVE-2025-9732.patch new file mode 100644 index 00000000..7065d636 --- /dev/null +++ b/debian/patches/0014-CVE-2025-9732.patch @@ -0,0 +1,22 @@ +Description: Fixed issue with commit 7ad81d69b. + Fixed an issue with recently committed changes that fix a problem with + invalid YBR_FULL images +Applied-Upstream: 3de96da6cd66b1af7224561c568bc3de50cd1398 +Author: Joerg Riesmeier +Last-Update: 2025-08-18 +Reviewed-By: Étienne Mollier + + +diff --git a/dcmimage/include/dcmtk/dcmimage/diybrpxt.h b/dcmimage/include/dcmtk/dcmimage/diybrpxt.h +index c5415c149..fdaaafc2d 100644 +--- a/dcmimage/include/dcmtk/dcmimage/diybrpxt.h ++++ b/dcmimage/include/dcmtk/dcmimage/diybrpxt.h +@@ -92,7 +92,7 @@ class DiYBRPixelTemplate + // attribute), but not more than the size of the intermediate buffer + const unsigned long count = (this->InputCount < this->Count) ? this->InputCount : this->Count; + // make sure that there is sufficient input data (for planar pixel data) +- if (!this->PlanarConfiguration || (count >= planeSize * 3 /* number of planes */)) ++ if (!this->PlanarConfiguration || (count >= planeSize)) + { + if (rgb) /* convert to RGB model */ + { diff --git a/debian/patches/series b/debian/patches/series index ec391766..9d0b2e02 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,3 +8,5 @@ remove_version.patch 0010-CVE-2025-25474.patch 0011-CVE-2025-25472.patch 0012-CVE-2025-2357.patch +0013-CVE-2025-9732.patch +0014-CVE-2025-9732.patch